<template>
    <div>
        <slot></slot>
    </div>
</template>

<script setup lang="ts">
import { AlignType, FormBasePropsType, FormProvided } from '@/types'
import { computed, provide, reactive } from 'vue'

interface PropsType extends FormBasePropsType {
    autoAlignLabel?: boolean
    labelWidth?: number
    labelAlign?: AlignType
}
const props = withDefaults(defineProps<PropsType>(), {
    color: undefined,
    disabled: undefined,
    size: undefined,
    sharp: undefined,
    autoAlignLabel: true,
    labelWidth: undefined,
    labelAlign: 'left',
})

interface StateType {
    validateFuncMap: Map<symbol, Function>
    labelWidthMap: Map<symbol, number>
}
const state = reactive<StateType>({
    validateFuncMap: new Map(),
    labelWidthMap: new Map(),
})

const myLabelWidth = computed(() => {
    if (props.autoAlignLabel) {
        return Array.from(state.labelWidthMap.values()).sort((a, b) => b - a)[0]
    }
    return props.labelWidth
})

const methods = {
    addValidateFunc(key: symbol, func: Function) {
        state.validateFuncMap.set(key, func)
    },
    removeValidateFunc(key: symbol) {
        state.validateFuncMap.delete(key)
    },
    addLabelWidth(key: symbol, width: number) {
        state.labelWidthMap.set(key, width)
    },
    removeLabelWidth(key: symbol) {
        state.labelWidthMap.delete(key)
    },
    async validate() {
        let hasError = false
        try {
            for (let func of state.validateFuncMap.values()) {
                await func()
            }
        } catch (error) {
            hasError = true
        }
        if (hasError) {
            throw new Error('Invalid form data.')
        }
    },
}

defineExpose({
    validate: methods.validate,
})

provide<FormProvided>(
    'form',
    computed(() => {
        return {
            color: props.color,
            disabled: props.disabled,
            size: props.size,
            sharp: props.sharp,
            removeValidateFunc: methods.removeValidateFunc,
            addValidateFunc: methods.addValidateFunc,
            labelAlign: props.labelAlign,
            myLabelWidth: myLabelWidth.value,
            addLabelWidth: methods.addLabelWidth,
            autoAlignLabel: props.autoAlignLabel,
            removeLabelWidth: methods.removeLabelWidth,
        }
    }),
)
</script>
